/**
 * @file wiz_socket.c
 * @brief wizchip 套接字基于FreeRTOS封装
 * @author wangh (wanghuan3037@fiberhome.com)
 * @version 1.0
 * @date 2020-11-09
 * @copyright Copyright (c) 2020  烽火通信
 ***************************************************************
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version  <th>Author  <th>Description
 * <tr><td>2020-11-09 <td>1.0      <td>wangh   <td>内容
 * </table>
 */ 
#include <stdbool.h>
#include "wiz_socket.h"
#include "wizchip_dns.h"
#include "wiz.h"

#undef LOG_LEVEL_
#define LOG_LEVEL_ 	LOG_LVL_ASSERT
#include "bsp_log.h"


extern bool wiz_init_ok;
#define WIZ_INIT_STATUS_CHECK                              \
    if (wiz_init_ok == false ||                            \
        (getPHYCFGR() & PHYCFGR_LNK_ON) != PHYCFGR_LNK_ON) \
    {                                                      \
        return SOCKERR_INIT_PHY;                           \
    }                                                      \



static wiz_socket_t sockets[WIZ_SOCKETS_NUM] = {0};   ///< 全局套接字信息结构体数组


/**
 * @brief 通过socket号获取套接字信息结构体
 * @param  socket      socket号
 * @return wiz_socket_t* 套接字信息结构体
 */
static wiz_socket_t *wiz_get_socket(uint8_t socket)
{
    if (socket >= WIZ_SOCKETS_NUM)
        return NULL;

    if (sockets[socket].magic != WIZ_SOCKET_MAGIC)
        return NULL;

    return &sockets[socket];
}

/**
 * @brief 分配初始化套接字信息结构体
 * @return wiz_socket_t* 套接字信息结构体
 */
static wiz_socket_t *alloc_socket(void)
{
    wiz_socket_t *sock = NULL;
    uint8_t idx = 0;
    static SemaphoreHandle_t alloc_socket_lock = NULL;  ///< 套接字结构体数组操作锁

    if ( alloc_socket_lock == NULL )
    {
        alloc_socket_lock = xSemaphoreCreateBinary();
        if( alloc_socket_lock == NULL )
        {
            log_e("alloc_socket_lock create error\r\n");
            return NULL;
        }
        xSemaphoreGive( alloc_socket_lock );
    }

    xSemaphoreTake( alloc_socket_lock, portMAX_DELAY );

    for (idx = 0; idx < WIZ_SOCKETS_NUM && sockets[idx].magic; idx++);
    if (idx == WIZ_SOCKETS_NUM)
    {
        xSemaphoreGive( alloc_socket_lock );
        log_e("sockets have use up, need close someone\r\n");
        return NULL;
    }

    sock = &(sockets[idx]);
    memset( sock, 0, sizeof(wiz_socket_t) );

    /* 创建数据接收通知信号量 */
    if( (sock->recv_notice = xSemaphoreCreateBinary()) == NULL )
    {
        xSemaphoreGive( alloc_socket_lock );
        log_e("socket%d recv_notice create error\r\n", idx);
        return NULL;
    }

    /* 创建接收锁 */
    if( (sock->recv_lock = xSemaphoreCreateBinary()) == NULL )
    {
        xSemaphoreGive( alloc_socket_lock );
        log_e("socket%d recv_notice create error\r\n", idx);
        return NULL;
    }
    xSemaphoreGive( sock->recv_lock );

    sock->magic = WIZ_SOCKET_MAGIC;
    sock->socket = idx;
    // sock->recv_timeout = portMAX_DELAY; /* 接收默认阻塞 */
    // sock->send_timeout = 10000;         /* 发送默认超时10s */

    xSemaphoreGive( alloc_socket_lock );
    return sock;
}

/**
 * @brief 芯片源IP地址检查，无效则重新初始化芯片
 * @return int8_t 
 */
int8_t wiz_sip_check(void)
{
    uint32_t taddr;
    getSIPR((uint8_t*)&taddr);
    if(taddr == 0)
    {
        wiz_config(NULL);
        return SOCKERR_SOCKINIT;
    }

    return SOCK_OK;
}

/**
 * @brief socket接收通知回调
 * @param  socket      socket号
 * @return int8_t 0：成功
 */
int8_t wiz_recv_notice_cb(uint8_t socket)
{
    // log_d("wiz_recv_notice_cb...\r\n");
    wiz_socket_t *sock = wiz_get_socket(socket);
    if (sock == NULL)
        return -1;

    xSemaphoreGive(sock->recv_notice);  ///< 通知有数据接收
    return 0;
}

/**
 * @brief socket断开通知回调
 * @param  socket      socket号
 * @return int8_t 0：成功
 */
int8_t wiz_closed_notice_cb(uint8_t socket)
{
    // log_d("wiz_closed_notice_cb...\r\n");
    wiz_socket_t *sock = wiz_get_socket(socket);
    if (sock == NULL)
        return -1;

    // uint8_t socket_state = getSn_SR(socket);
    // if (socket_state != SOCK_CLOSE_WAIT)
    // {
    //     log_e("socket(%d) recv close but not SOCK_CLOSE_WAIT\r\n", socket);
    //     return -1;
    // }

    if (wizchip_close(socket) != SOCK_OK)
    {
        log_e("socket(%d) close failed.\r\n", socket);
        return -1;
    }

    xSemaphoreGive(sock->recv_notice);
    return 0;
}

/**
 * @brief phy断开通知回调
 */
void wiz_linkDown_notice_cb( void )
{
    for (uint8_t idx = 0; idx < WIZ_SOCKETS_NUM; idx++)
    {
        if (sockets[idx].magic == WIZ_SOCKET_MAGIC)
        {
            wiz_closed_notice_cb(idx);
        }
    }
}

/**
 * @brief 创建套接字
 * @param[in]  protocol 协议 @ref Sn_MR_TCP @ref Sn_MR_UDP
 * @param[in]  port     端口号
 * @param[in]  flag     套接字标志(0 Sn_MR_ND)
 * @return int8_t 
 * - @b Sucess : 套接字号（0~7） \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_ALLOC_SOCK - 套接字分配失败
 * - @ref SOCKERR_SOCKSTATUS - sock状态异常
 * - @ref SOCKERR_SOCKMODE - sock模式不支持
 * - @ref SOCKERR_SOCKINIT - IP未设置
 */
int8_t wiz_socket( uint8_t protocol, uint16_t port, uint8_t flag )
{
    wiz_socket_t *sock = NULL;
    int8_t ret;

    /* 检查 wizchip 是否初始化 */
    if(!wiz_init_ok)
        return SOCKERR_INIT_PHY;

    sock = alloc_socket();
    if (sock == NULL)
    {
        log_e("allocate a new WIZnet socket failed!\r\n");
        return SOCKERR_ALLOC_SOCK;
    }
    sock->protocol = protocol;
    sock->port = port;

    switch (protocol)
    {
    case Sn_MR_TCP:
        ret = wizchip_socket(sock->socket, protocol, port, Sn_MR_ND);
        if (ret != sock->socket)
        {
            log_e("WIZnet TCP socket(%d) create failed(%d)!\r\n", sock->socket, ret);
            if (ret == SOCKERR_SOCKINIT)    /* SIP 异常，w5500异常重启 */
            {
                wiz_config(NULL);
            }
            wiz_close(sock->socket);
            return ret;
        }
        break;

    case Sn_MR_UDP:
    case Sn_MR_IPRAW:
        ret = wizchip_socket(sock->socket, protocol, port, 0);
        if (ret != sock->socket)
        {
            log_e("WIZnet UDP socket(%d) create failed(%d)!\r\n", sock->socket, ret);
            if (ret == SOCKERR_SOCKINIT)    /* SIP 异常，w5500异常重启 */
            {
                wiz_config(NULL);
            }
            wiz_close(sock->socket);
            return ret;
        }
        break;

    default:
        log_e("Socket (%d) protocol %d is not support.\r\n", sock->socket, protocol);
        return SOCKERR_SOCKMODE;
    }

    return sock->socket;
}

/**
 * @brief 释放套接字系统资源
 * @param  sock        socket结构体
 */
static void free_socket(wiz_socket_t *sock)
{
    if (sock->recv_notice)
        vSemaphoreDelete( sock->recv_notice );

    if (sock->recv_lock)
        vSemaphoreDelete( sock->recv_lock );

    if (sock->tcps_tmr)
        xTimerDelete( sock->tcps_tmr, 0 );

    memset(sock, 0x00, sizeof(wiz_socket_t));
}

/**
 * @brief 关闭套接字,释放资源
 * @param[in]  socket   socket号
 * @return int8_t 
 * - @b Sucess : SOCK_OK \n
 * - @b Fail
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 */
int8_t wiz_close(uint8_t socket)
{
    wiz_socket_t *sock = NULL;

#if 0
    WIZ_INIT_STATUS_CHECK;  /* 检查初始化和PHY状态 */
#endif

    if( (sock = wiz_get_socket(socket)) == NULL )
        return SOCKERR_GET_SOCK;
    
    if( getSn_SR(socket) == SOCK_CLOSED )
    {
        free_socket(sock);
        return SOCK_OK;
    }

    if (wizchip_close(socket) != SOCK_OK)
    {
        log_e("WIZnet socket(%d) close failed.\r\n", socket);
        free_socket(sock);
        return SOCKERR_SOCKCLOSED;
    }

    free_socket(sock);
    return SOCK_OK;
}

/**
 * @brief TCP服务器维护定时处理函数
 * @param  xTimer       套接字参数
 */
static void wiz_tcps_timer_handler(TimerHandle_t xTimer)
{
    wiz_socket_t *sock = (wiz_socket_t *)pvTimerGetTimerID(xTimer);
    // log_e("wiz_tcps_timer_handler socket(%d)(%d)  (%d)!\r\n", sock->socket, sock->port, getSn_SR(sock->socket));
    switch (getSn_SR(sock->socket))
    {
    case SOCK_INIT:
        wizchip_listen(sock->socket);
        break;
    
    case SOCK_CLOSE_WAIT:   /* socket等待关闭状态 */
        break;

    case SOCK_CLOSED:       /* socket关闭 */
        wizchip_socket(sock->socket, Sn_MR_TCP, sock->port, Sn_MR_ND);
        break;

    default:
        break;
    }
}

/**
 * @brief 启动TCP服务器 \n
 * 维护TCP套接字资源，维护TCP连接
 * @param[in]  port     服务器端口
 * @return int8_t 
 * - @b Sucess : socket号 \n
 * - @b Fail : @ref wiz_socket \n
 * - @ref SOCKERR_NO_MEM - 内存不足
 */
int8_t wiz_tcpServer_start( uint16_t port )
{
    int8_t socket;

    if ((socket = wiz_socket( Sn_MR_TCP, port, Sn_MR_ND )) < 0)
    {
        log_e("TCP server start wiz_socket failed(%d)!\r\n", socket);
        return socket;
    }

    wiz_socket_t *sock = wiz_get_socket(socket);

    sock->tcps_tmr = xTimerCreate("tcps_tmr", pdMS_TO_TICKS(100), pdTRUE, (void *)sock, wiz_tcps_timer_handler);
    if(sock->tcps_tmr == NULL)
    {
        log_e("tcpServer(%d) create tcps_tmr error!\r\n", socket);
        wiz_close(socket);
        return SOCKERR_NO_MEM;
    }
    xTimerStart( sock->tcps_tmr, 0 );

    return socket;
}

/**
 * @brief 套接字连接（only for TCP）
 * @param[in]  socket   socket号
 * @param[in]  addr     目的IP
 * @param[in]  port     目的端口
 * @return int8_t 
 * - @b Sucess : SOCK_OK \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKINIT - 不是INIT状态
 */
int8_t wiz_connect(uint8_t socket, uint8_t * addr, uint16_t port)
{
    WIZ_INIT_STATUS_CHECK;  /* 检查初始化和PHY状态 */

    if (SOCKERR_SOCKINIT == wiz_sip_check())
        return SOCKERR_SOCKINIT;

    wiz_socket_t *sock = wiz_get_socket(socket);
    if (sock == NULL)
        return SOCKERR_GET_SOCK;

    /* 判断是否为TCP调用 */
    if (sock->protocol != Sn_MR_TCP)
    {
        log_e("wiz_connect only use for protocol TCP!\r\n");
        return SOCKERR_SOCKMODE;
    }

    /* 套接字寄存器状态处理 */
    uint8_t socket_state = getSn_SR(socket);
    if (socket_state != SOCK_INIT)
    {
        log_e("WIZnet connect failed, get socket(%d) register state(%d) error.\r\n", socket, socket_state);
        return SOCKERR_SOCKINIT;
    }

    int8_t ret = wizchip_connect(socket, addr, port);
    if (ret != SOCK_OK)
    {
        log_e("WIZnet socket(%d) connect failed(%d).\r\n", socket, ret);
        return ret;
    }

    return SOCK_OK;
}

/**
 * @brief 套接字断开连接（only for TCP）
 * @param[in]  socket   socket号
 * @return int8_t 
 * - @b Sucess : SOCK_OK \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKSTATUS - 不是 SOCK_ESTABLISHED 状态
 */
int8_t wiz_disconnect(uint8_t socket)
{
    WIZ_INIT_STATUS_CHECK;  /* 检查初始化和PHY状态 */

    if (SOCKERR_SOCKINIT == wiz_sip_check())
        return SOCKERR_SOCKINIT;

    wiz_socket_t *sock = wiz_get_socket(socket);
    if (sock == NULL)
        return SOCKERR_GET_SOCK;

    /* 判断是否为TCP调用 */
    if (sock->protocol != Sn_MR_TCP)
    {
        log_e("wiz_connect only use for protocol TCP!\r\n");
        return SOCKERR_SOCKMODE;
    }

    /* 套接字寄存器状态处理 */
    uint8_t socket_state = getSn_SR(socket);
    if (socket_state != SOCK_ESTABLISHED)
    {
        log_e("WIZnet disconnect failed, get socket(%d) register state(%d) error.\r\n", socket, socket_state);
        return SOCKERR_SOCKSTATUS;
    }

    int8_t ret = wizchip_disconnect(socket);
    if (ret != SOCK_OK)
    {
        log_e("WIZnet socket(%d) disconnect failed(%d).\r\n", socket, ret);
        return ret;
    }

    return SOCK_OK;
}

/**
 * @brief 数据报套接字发送
 * @param[in]  socket   socket号
 * @param[in]  buf      发送缓存
 * @param[in]  len      发送长度
 * @param[in]  addr     目标IP
 * @param[in]  port     目标端口
 * @return int32_t 
 * - @b Sucess : 实际发送长度 \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKSTATUS - 非 SOCK_UDP 状态
 * - @ref SOCKERR_SOCKCLOSED - 套接字非法关闭
 * - @ref SOCK_BUSY - 套接字忙
 * - @ref SOCKERR_TIMEOUT - 发送超时
 */
int32_t wiz_sendto(uint8_t socket, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port)
{
    WIZ_INIT_STATUS_CHECK;  /* 检查初始化和PHY状态 */

    if (SOCKERR_SOCKINIT == wiz_sip_check())
        return SOCKERR_SOCKINIT;

    if (buf == NULL || len == 0 || addr == NULL)
    {
        log_e("WIZnet recvfrom input data or length error!\r\n");
        return SOCKERR_PARAM;
    }

    wiz_socket_t *sock = wiz_get_socket(socket);
    if (sock == NULL)
        return SOCKERR_GET_SOCK;

    /* 判断是否为UDP调用 */
    if (sock->protocol != Sn_MR_UDP && sock->protocol != Sn_MR_IPRAW)
    {
        log_e("wiz_sendto only use for protocol UDP or IPRAW!\r\n");
        return SOCKERR_SOCKMODE;
    }

    /* 套接字寄存器状态处理 */
    uint8_t socket_state = getSn_SR(socket);
    if (socket_state != SOCK_UDP && socket_state != SOCK_IPRAW)
    {
        log_e("WIZnet sendto failed, get socket(%d) register state(%d) error.\r\n", socket, socket_state);
        return SOCKERR_SOCKSTATUS;
    }

    int32_t send_len = 0;
    if ((send_len = wizchip_sendto(socket, buf, len, addr, port)) <= 0)
    {
        log_e("WIZnet socket(%d) send data failed(%d).\r\n", socket, send_len);
        return send_len;
    }

    return send_len;
}

/**
 * @brief 数据流套接字发送
 * @param[in]  socket   socket号
 * @param[in]  buf      发送缓存
 * @param[in]  len      发送长度
 * @return int32_t 
 * - @b Sucess : 实际发送长度 \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_PARAM - 错误入参
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKSTATUS - 非 SOCK_ESTABLISHED 状态
 * - @ref SOCKERR_SOCKCLOSED - 套接字非法关闭
 * - @ref SOCK_BUSY - 套接字忙
 * - @ref SOCKERR_TIMEOUT - 发送超时
 */
int32_t wiz_send(uint8_t socket, uint8_t * buf, uint16_t len)
{
    WIZ_INIT_STATUS_CHECK;  /* 检查初始化和PHY状态 */

    if (SOCKERR_SOCKINIT == wiz_sip_check())
        return SOCKERR_SOCKINIT;

    if (buf == NULL || len == 0)
    {
        log_e("WIZnet recvfrom input data or length error!\r\n");
        return SOCKERR_PARAM;
    }

    wiz_socket_t *sock = wiz_get_socket(socket);
    if (sock == NULL)
        return SOCKERR_GET_SOCK;

    /* 判断是否为TCP调用 */
    if (sock->protocol != Sn_MR_TCP)
    {
        log_e("wiz_send only use for protocol TCP!\r\n");
        return SOCKERR_SOCKMODE;
    }

    /* 套接字寄存器状态处理 */
    uint8_t socket_state = getSn_SR(socket);
    if (socket_state == SOCK_CLOSED)
        return SOCKERR_SOCKCLOSED;
    else if (socket_state != SOCK_ESTABLISHED)
    {
        log_e("WIZnet recvfrom failed, get socket(%d) register state(%d) error.\r\n", socket, socket_state);
        return SOCKERR_SOCKSTATUS;
    }

    int32_t send_len = 0;
    if ((send_len = wizchip_send(socket, buf, len)) < 0)
    {
        log_e("WIZnet socket(%d) send data failed(%d).\r\n", socket, send_len);
        return send_len;
    }

    return send_len;
}

/**
 * @brief 数据报套接字接收
 * @param[in]  socket   socket号
 * @param[in]  buf      接收缓存
 * @param[in]  len      接收长度
 * @param[out] addr     远程ip地址
 * @param[out] port     远程端口
 * @param[in]  timeout  接收超时时间（ms）
 * - 0 立即返回
 * - portMAX_DELAY 一直阻塞
 * @return int32_t 
 * - @b Sucess : 实际接收的长度 \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_PARAM - 错误入参
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKSTATUS - 非 SOCK_UDP 状态
 * - @ref SOCKERR_SOCKCLOSED - 套接字非法关闭
 * - @ref SOCK_BUSY - 套接字忙
 * - @ref SOCKERR_TIMEOUT - 接收超时
 */
int32_t wiz_recvfrom(uint8_t socket, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port, uint32_t timeout)
{
    int32_t recv_len = 0;

    WIZ_INIT_STATUS_CHECK;  /* 检查初始化和PHY状态 */

    if (SOCKERR_SOCKINIT == wiz_sip_check())
        return SOCKERR_SOCKINIT;

    /* 检查入参 */
    if (buf == NULL || len == 0 || addr == NULL || port == NULL)
    {
        log_e("WIZnet recvfrom input data or length error!\r\n");
        return SOCKERR_PARAM;
    }

    wiz_socket_t *sock = wiz_get_socket(socket);
    if (sock == NULL)
        return SOCKERR_GET_SOCK;

    /* 判断是否为UDP调用 */
    if (sock->protocol != Sn_MR_UDP && sock->protocol != Sn_MR_IPRAW)
    {
        log_e("wiz_recvfrom only use for protocol UDP or IPRAW!\r\n");
        return SOCKERR_SOCKMODE;
    }

    /* 套接字寄存器状态处理 */
    uint8_t socket_state = getSn_SR(socket);
    if (socket_state != SOCK_UDP && socket_state != SOCK_IPRAW)
    {
        log_e("WIZnet recvfrom failed, get socket(%d) register state(%d) error.\r\n", socket, socket_state);
        return SOCKERR_SOCKSTATUS;
    }

    /* 等待接收通知 */
    if (xSemaphoreTake(sock->recv_notice, timeout) == pdFAIL)
    {
        log_e("WIZnet socket (%d) receive timeout (%d)!\r\n", socket, timeout);
        return SOCKERR_TIMEOUT;
    }
    else
    {
        uint16_t recvsize = getSn_RX_RSR(socket);
        if (recvsize > 0)
        {
            socket_state = getSn_SR(socket);
            if (socket_state != SOCK_CLOSED)    /* SOCK_UDP */
            {
                recv_len = wizchip_recvfrom(socket, buf, len, addr, port);
                if (recv_len < 0)
                {
                    log_e("WIZnet socket(%d) receive data failed(%d).\r\n", socket, recv_len);
                    return recv_len;
                }
            }
            else
                return SOCKERR_SOCKCLOSED;
        }
    }

    return recv_len;
}

/**
 * @brief 数据流套接字接收
 * @param[in]  socket   socket号
 * @param[in]  buf      接收缓存
 * @param[in]  len      接收长度
 * @param[in]  timeout  接收超时时间（ms）
 * - 0 立即返回
 * - portMAX_DELAY 一直阻塞
 * @return int32_t 
 * - @b Sucess : 实际接收的长度 \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_PARAM - 错误入参
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKSTATUS - 非 SOCK_ESTABLISHED 状态
 * - @ref SOCKERR_SOCKCLOSED - 套接字非法关闭
 * - @ref SOCK_BUSY - 套接字忙
 * - @ref SOCKERR_TIMEOUT - 接收超时
 */
int32_t wiz_recv(uint8_t socket, uint8_t * buf, uint16_t len, uint32_t timeout)
{
    int32_t recv_len = 0;

    WIZ_INIT_STATUS_CHECK;  /* 检查初始化和PHY状态 */

    if (SOCKERR_SOCKINIT == wiz_sip_check())
        return SOCKERR_SOCKINIT;

    /* 检查入参 */
    if (buf == NULL || len == 0)
    {
        log_e("WIZnet recvfrom input data or length error!\r\n");
        return SOCKERR_PARAM;
    }

    wiz_socket_t *sock = wiz_get_socket(socket);
    if (sock == NULL)
        return SOCKERR_GET_SOCK;

    /* 判断是否为TCP调用 */
    if (sock->protocol != Sn_MR_TCP)
    {
        log_e("wiz_recv only use for protocol TCP!\r\n");
        return SOCKERR_SOCKMODE;
    }

    /* 获取接收缓存大小 */
    uint16_t recvsize = getSn_RX_RSR(socket);
    if (recvsize > 0)
    {
        xSemaphoreTake( sock->recv_lock, portMAX_DELAY );
        recv_len = wizchip_recv(socket, buf, len);
        xSemaphoreGive( sock->recv_lock );
        if (recv_len > 0)
            return recv_len;
    }

    /* 套接字寄存器状态处理 */
    uint8_t socket_state = getSn_SR(socket);
    if (socket_state == SOCK_CLOSED)
        return SOCKERR_SOCKCLOSED;
    else if (socket_state != SOCK_ESTABLISHED)
    {
        log_e("WIZnet receive failed, get socket(%d) register state(%d) error.\r\n", socket, socket_state);
        return SOCKERR_SOCKSTATUS;
    }

    /* 等待接收通知 */
    if (xSemaphoreTake(sock->recv_notice, timeout) == pdFAIL)
    {
        log_e("WIZnet socket (%d) receive timeout (%d)!\r\n", socket, timeout);
        return SOCKERR_TIMEOUT;
    }
    else
    {
        socket_state = getSn_SR(socket);
        if (socket_state == SOCK_ESTABLISHED)
        {
            recvsize = getSn_RX_RSR(socket);
            if (recvsize > 0)
            {
                xSemaphoreTake( sock->recv_lock, portMAX_DELAY );
                recv_len = wizchip_recv(socket, buf, len);
                xSemaphoreGive( sock->recv_lock );
            }
            if (recv_len < 0)
            {
                log_e("WIZnet socket(%d) receive data failed(%d).\r\n", socket, recv_len);
                return recv_len;
            }
        }
        else if (socket_state == SOCK_CLOSED)
        {
            log_e("WIZnet socket(%d) receive but closed.\r\n", socket);
            return SOCKERR_SOCKCLOSED;
        }
        else
        {
            return SOCKERR_SOCKSTATUS;
        }
    }

    return recv_len;
}

#if WIZ_USING_DNS
/**
 * @brief 域名解析
 * @param[in]  name         域名
 * @param[in]  ip_from_dns  解析IP
 * @return int8_t 
 * - @b Sucess : 0 \n
 * - @b Fail : -1
 */
int8_t wiz_gethostbyname(const char *name, uint8_t * ip_from_dns)
{
    int8_t ret = 0;
    size_t idx = 0;
    uint8_t data_buffer[MAX_DNS_BUF_SIZE];

    WIZ_INIT_STATUS_CHECK;  /* 检查初始化和PHY状态 */

    if (SOCKERR_SOCKINIT == wiz_sip_check())
        return SOCKERR_SOCKINIT;

    if ((name == NULL) || (ip_from_dns == NULL))
        return -1;

    if (strlen(name) > MAX_DOMAIN_NAME)
    {
        log_e("Domain name lenght is too big.\r\n");
        return -1;
    }

    /* 查找可用socket */
    for (idx = 0; idx < WIZ_SOCKETS_NUM && sockets[idx].magic; idx++);
    if (idx >= WIZ_SOCKETS_NUM)
    {
        log_e("WIZnet DNS failed, socket number is full.\r\n");
        return -1;
    }

    wiz_NetInfo net_info;
    ctlnetwork(CN_GET_NETINFO, (void *)&net_info);

    DNS_init(idx, data_buffer); /* DNS客户端初始化 */
    ret = DNS_run(net_info.dns, (uint8_t *)name, ip_from_dns);
    if(ret == -1)
    {
        log_e("Domain name lenght is too big, MAX_DOMAIN_NAME should be redefined it.\r\n");
        return -1;
    }
    else if(ret == 0)
    {
        log_e("parseDNS timeout or Parse error.\r\n");
        return -1;
    }

    if (ip_from_dns[0] == 0)
        return -1;

    return 0;
}
#endif



/*********** (C) COPYRIGHT 2020 FiberHome *****END OF FILE****/
